home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1 / Nebula One.iso / Mail / pine3.92 / pico / msmem.c < prev    next >
C/C++ Source or Header  |  1995-04-24  |  28KB  |  1,302 lines

  1. #ifndef    MSC_MALLOC
  2.  
  3. #define WIN31
  4. #define STRICT
  5.  
  6. #include <windows.h>
  7. #include <toolhelp.h>
  8. #include <stdio.h>
  9.  
  10. #include "mswin.h"
  11.  
  12.  
  13.  
  14.  
  15.  
  16. /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  17.  *
  18.  *                  Memory allocation routines.
  19.  *
  20.  *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
  21.  
  22. /*
  23.  *    The plan is to allocate small blocks in the local heap and
  24.  *    large blocks in the global heap.  The intention is to keep
  25.  *    the number of global allocations to a minimum.
  26.  *
  27.  *    The boundry between small memory and large memory is
  28.  *    controld by the constant SMALL_MEM_BOUNDRY.  Blocks smaller
  29.  *    than SMALL_MEM_BOUNDRY go into the local heap.  This should
  30.  *    be set large enough to capture the majority of small memory
  31.  *    blocks in the local heap.  But if it is too large, the local 
  32.  *    heap will fill up and we will end up allocating a lot of small
  33.  *    blocks in the global heap.
  34.  *
  35.  *    Unfortunatly, pine seems to need a large stack.  With the
  36.  *    stack, some global data, and the heap all cramed in to a 64K
  37.  *    segment we end up with a heap that is smaller than ideal.
  38.  *    This could be improved by reducing the size of the stack, or
  39.  *    by moving the heap to a seperate memory block.  I did a little
  40.  *    work on moving the heap, but was not successful.  My attepts
  41.  *    can be seen in the function MemATest().
  42.  *
  43.  *    Currently (7/8/94) I've set the stack to 32K (in pine/makefile.win),
  44.  *    the heap to 12K, and the small memory boundry to 32 bytes.
  45.  *    Statistics on pine memory allocation suggest that it would be better
  46.  *    to have a 25K local heap and a 95 byte small memory boundry.
  47.  *
  48.  *    Statistics on memory use can be gathered by logging memory debugging
  49.  *    to a file, then running the following awk script:
  50.  *
  51.  
  52.   # mem.awk
  53.   #
  54.   #    Looks through log and find blocks that were allocated but not
  55.   #    freed uses block id numbers, rather than addresses, since this is
  56.   #    more accurate (and since this is what block ids exist!)
  57.   #
  58.   #    awk may run out of memory if the logfile gets too big.  If this
  59.   #    happens, then another strategy will be needed...
  60.   #
  61.  
  62.   BEGIN {
  63.       FS = "[ ()]+";
  64.  
  65.       b[0] = 16;
  66.       b[1] = 32;
  67.       b[2] = 64;
  68.       b[3] = 96;
  69.       b[4] = 128;
  70.       b[5] = 256;
  71.       b[6] = 512;
  72.       b[7] = 1024;
  73.       b[8] = 2048;
  74.       b[9] = 4096;
  75.       b[10] = 9600;
  76.       b[11] = 20000;
  77.       b[12] = 40000;
  78.       b[13] = 80000;
  79.       b[14] = 200000000;
  80.       b[15] = 0;
  81.       bcount = 15;
  82.       for (i = 0; i < bcount; ++i)
  83.           c[i] = 0;
  84.  
  85.       maxmem = 0;
  86.       maxsmallmem = 0;
  87.  
  88.       allocs = 0;
  89.       frees = 0;
  90.       globalallocs = 0;
  91.       pallocs = 0;
  92.       pfrees = 0;
  93.   }
  94.  
  95.   {
  96.       #print "one", $1, "two", $2, "three", $3, "four ", $4, "five ", $5;
  97.       if( $1 == "MemAlloc:" ) {
  98.           m[$5] = $0;
  99.  
  100.           ++allocs;
  101.           if ($9 == 1) ++globalallocs;
  102.  
  103.           for (i = 0; i < bcount; ++i) {
  104.               if (b[i] > $7) {
  105.                   ++c[i];
  106.                   break;
  107.               }
  108.           }
  109.       }
  110.       else if( $1 == "MemFree:" ) {
  111.           delete m[$5];
  112.           ++frees;
  113.       }
  114.       if( $1 == "PageAlloc:" ) {
  115.           p[$5] = $0;
  116.  
  117.           ++pallocs;
  118.       }
  119.       else if( $1 == "PageFree:" ) {
  120.           delete p[$5];
  121.           ++pfrees;
  122.       }
  123.       else if ($1 == "Memory") {
  124.           if ($6 > maxmem) maxmem = $6;
  125.       }
  126.       else if ($1 == "Small") {
  127.           if ($7 > maxsmallmem) maxsmallmem = $7;
  128.       }
  129.   }
  130.  
  131.  
  132.   END {
  133.       for( i in m ) {
  134.           print m[i]
  135.       }
  136.       for (i in p) {
  137.           print p[i]
  138.       }
  139.  
  140.       cumulative = 0;
  141.       for (i = 0; i < bcount; ++i) {
  142.           cumulative += c[i];
  143.           printf "%9d : %5d  (%5d)\n", b[i], c[i], cumulative;
  144.       }
  145.  
  146.       print;
  147.       print "Max memory use:        ", maxmem;
  148.       print "Max small memory use:  ", maxsmallmem;
  149.       print;
  150.       print "Local allocations   ", allocs - globalallocs;
  151.       print "Global allocations  ", globalallocs;
  152.       print "Total allocations   ", allocs;
  153.       print "Total memory frees  ", frees;
  154.       print "Blocks not freed    ", allocs - frees;
  155.       print;
  156.       print "Page allocations    ", pallocs;
  157.       print "Page frees          ", pfrees;
  158.       print "Pages not freed     ", pallocs - pfrees;
  159.   }
  160.  
  161.  *
  162.  *    Each memory block is assigned a unique id.  This is only used
  163.  *    to match allocations with frees in the debug log.
  164.  */
  165.  
  166.  
  167.  
  168. /*
  169.  * SEGHEAP selectes between two different implementations of the memory 
  170.  * management functions.  Defined and it uses a sub allocation scheme.
  171.  * Undefined and it comples a direct allocation scheme.
  172.  *
  173.  * The sub allocation scheme is greatly prefered because it greatly reduces
  174.  * the number of global memory allocations.
  175.  */
  176. #define SEGHEAP        /* Use the sub allocation scheme. */
  177.  
  178.  
  179.  
  180.  
  181. #define  MEM_DEBUG            /* Compile in memory debugging code.*/
  182. #define MEM_DEBUG_LEVEL        8    /* Pine debug level at which memory
  183.                      * debug messages will be generated.*/
  184. #ifdef MEM_DEBUG
  185. static int        MemDebugLevel = 0;    /* Doing debugging. */
  186. static FILE        *MemDebugFile = NULL;    /* File to write to. */
  187. #endif
  188.  
  189.  
  190.  
  191. #ifdef DEBUG
  192. #define LOCAL
  193. #else
  194. #define LOCAL        static
  195. #endif
  196.  
  197.  
  198. #define GET_SEGMENT(x)        (0xffff & ((DWORD)(x) >> 16))
  199. #define GET_OFFSET(x)        (0xffff & (DWORD)(x))
  200.  
  201.  
  202. #undef malloc
  203. #undef realloc
  204. #undef free
  205.  
  206.  
  207. void        MemATest (void);
  208.  
  209.  
  210.  
  211.  
  212.  
  213. /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  214.  *
  215.  *    Standard memory allcation functions.
  216.  *
  217.  *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
  218.  
  219.  
  220. void *
  221. malloc (size_t size)
  222. {
  223.     return (MemAlloc (size));
  224. }
  225.  
  226.  
  227. void __far *
  228. _fmalloc (size_t size)
  229. {
  230.     return (MemAlloc (size));
  231. }
  232.  
  233.  
  234. void __far *
  235. realloc (void *memblock, size_t size)
  236. {
  237.     return (MemRealloc (memblock, size));
  238. }
  239.  
  240.  
  241. void __far *
  242. _frealloc (void *memblock, size_t size)
  243. {
  244.     return (MemRealloc (memblock, size));
  245. }
  246.  
  247.  
  248. void 
  249. free (void *memblock)
  250. {
  251.     MemFree (memblock);
  252. }
  253.  
  254. void 
  255. _ffree (void *memblock)
  256. {
  257.     MemFree (memblock);
  258. }
  259.  
  260.  
  261. /*
  262.  * Turn on memory debugging and specify file to write to.
  263.  */
  264. void
  265. MemDebug (int debug, FILE *debugFile)
  266. {
  267. #ifdef MEM_DEBUG
  268.     if (debugFile == NULL) {
  269.     MemDebugLevel = 0;
  270.     MemDebugFile = NULL;
  271.     }
  272.     else {
  273.     MemDebugLevel = debug;
  274.     MemDebugFile = debugFile;
  275.     fprintf (MemDebugFile, "Memory Debuging set on\n");
  276.     }
  277. #endif /* MEM_DEBUG */
  278. }
  279.  
  280.  
  281.  
  282.  
  283.  
  284.  
  285.  
  286. #ifdef SEGHEAP
  287.  
  288. /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  289.  *
  290.  *                  SEGHEAP Memory allocation routines.
  291.  *
  292.  *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
  293.  
  294. /*
  295.  * This implementation allocates memory in pages then sub alloates from the
  296.  * pages.  This greatly reduces the number of global memory blocks allocated.
  297.  * This code originally written by Stephen Chung and posted to a Usenet news
  298.  * group.  I've modified them for use in Pine.  The author says:
  299.  *
  300.  * 
  301.  * Copyright (C) Stephen Chung, 1991-1992.  All rights reserved. 
  302.  *
  303.  * Afterwords
  304.  * ----------
  305.  * 
  306.  * Theoretically, you are required to obtain special approval from me (because
  307.  * I copyrighted these routines) if you want to use them in your programs.
  308.  * However, I usually don't really care if you are not using these routines in
  309.  * a commercial, shareware etc. product.
  310.  * 
  311.  * Any questions and/or bug fixes, please send email to:
  312.  * 
  313.  *         Stephen Chung           stephenc@cunixf.cc.columbia.edu
  314.  * 
  315.  * If it bounces, then try schung@cogsci.Berkeley.EDU
  316.  * 
  317.  * Have fun!
  318.  * 
  319.  */
  320.  
  321.  
  322. /*
  323.  * The folloing control debugging code for testing out of memory conditions.
  324.  * there are to test code.
  325.  *
  326.  * MEM_ALLOC_LIMT 
  327.  *    Setting this to anything other than zero will limit memory allocation
  328.  *    to (rougly) that many bytes.
  329.  *
  330.  * MEM_FAIL_SOON
  331.  *    Compiles in a function which will cause the memory allocation to fail
  332.  *    soon after that function is called.  this can be used to test
  333.  *    mem alloc failurs in specific code segments.
  334.  */
  335. #define MEM_ALLOC_LIMIT        0
  336. #define MEM_FAIL_SOON        0
  337.  
  338.  
  339. #if MEM_FAIL_SOON
  340. static long MemFailSoonLimit = 0;
  341. #endif
  342.  
  343.  
  344.  
  345. #define MAGIC           0x42022667
  346. #define MAGIC2        0x56743296
  347.  
  348. typedef struct MemoryStruct {
  349.     long int        magic;
  350.     void far        *page;
  351.     WORD        id;
  352.     MemSize        size;
  353.     BOOL        allocated;
  354.     struct MemoryStruct far *next, far *prev;
  355.     long int        magic2;
  356. } MEMHEADER;
  357.  
  358. typedef struct PageHeaderStruct {
  359.     long int        magic;
  360.     HANDLE        handle;
  361.     WORD        id;
  362.     MemSize        size;
  363.     MemSize        used;
  364.     MemSize        overhead;
  365.     MEMHEADER far    *data, far *empty;
  366.     struct PageHeaderStruct far *next, far *prev;
  367.     long int        magic2;
  368. } MEMPAGEHEADER;
  369.  
  370. typedef struct {
  371.     MEMPAGEHEADER far *pages;
  372.     int nr_pages;
  373. } MAINMEMHEADER;
  374.  
  375. #define PAGESIZE        (6 * 1024)
  376. #define USEABLESIZE     (PAGESIZE - sizeof(MEMPAGEHEADER) - sizeof(MEMHEADER))
  377.  
  378.  
  379. LOCAL MAINMEMHEADER    MemHeader = { NULL, 0 };
  380. LOCAL WORD        MemID = 0;        /* Keep track of ID. */
  381. LOCAL WORD        PageID = 0;
  382. LOCAL unsigned long    MemInUse = 0;        /* Total bytes in use. */
  383. LOCAL unsigned long    MemInUseMax = 0;    /* max in use at one time. */
  384. LOCAL unsigned long     PageMemInUse = 0;
  385. LOCAL unsigned long    PageMemInUseMax = 0;
  386.  
  387.  
  388.  
  389. static MEMPAGEHEADER far *
  390. AddPage(MemSize n)
  391. {
  392.     void far *cp;
  393.     MEMHEADER far *mp;
  394.     MEMPAGEHEADER far *p;
  395.     HANDLE handle = NULL;
  396.     
  397.     
  398. #if MEM_ALLOC_LIMIT
  399.     if (n + PageMemInUse > MEM_ALLOC_LIMIT) {
  400.     MessageBox (NULL, "PageAlloc:  Above preset limit, allocation fails", 
  401.         "Out Of Memory", MB_ICONSTOP | MB_OK);
  402.     return (NULL);
  403.     }
  404. #endif
  405.  
  406.     handle = GlobalAlloc(GHND, n);
  407.     if (handle == NULL) {
  408. #ifdef MEM_DEBUG
  409.     if (MemDebugLevel >= 1) 
  410.         fprintf (MemDebugFile, "***\n*** Out of memory: allocating %d bytes\n***\n", n);
  411. #endif
  412.         return (NULL);
  413.     }
  414.  
  415.     if (MemHeader.pages == NULL || MemHeader.nr_pages <= 0) {
  416.         p = MemHeader.pages = (MEMPAGEHEADER far *) GlobalLock(handle);
  417.         p->prev = NULL;
  418.     } else {
  419.         for (p = MemHeader.pages; p->next != NULL; p = p->next);
  420.         p->next = (MEMPAGEHEADER far *) GlobalLock(handle);
  421.         p->next->prev = p;
  422.         p = p->next;
  423.     }
  424.  
  425.     p->magic = MAGIC;
  426.     p->handle = handle;
  427.     p->next = NULL;
  428.     p->id = PageID++;
  429.     p->size = n;
  430.     p->used = 0;
  431.     p->overhead = sizeof(MEMPAGEHEADER) + sizeof(MEMHEADER);
  432.     p->magic2 = MAGIC2;
  433.  
  434.     cp = ((char far *) p) + sizeof(MEMPAGEHEADER);
  435.     mp = (MEMHEADER far *) cp;
  436.  
  437.     p->data = p->empty = mp;
  438.  
  439.     mp->magic = 0L;
  440.     mp->magic2 = 0L;
  441.     mp->allocated = FALSE;
  442.     mp->page = p;
  443.     mp->size = p->size - p->overhead;
  444.     mp->next = mp->prev = NULL;
  445.  
  446.     MemHeader.nr_pages++;
  447.     
  448.  
  449. #ifdef MEM_DEBUG
  450.     if (MemDebugLevel >= MEM_DEBUG_LEVEL) {
  451.     fprintf (MemDebugFile, "PageAlloc: addr(%lx) id(%u) size(%ld) global(%d)\n",
  452.         p, p->id, (long)n, 1);
  453.     fflush (MemDebugFile);
  454.     }
  455. #endif /* MEM_DEBUG */
  456.  
  457.     PageMemInUse += n;
  458.     if (PageMemInUse > PageMemInUseMax)
  459.     PageMemInUseMax = PageMemInUse;
  460.     
  461.  
  462.     return (p);
  463. }
  464.  
  465.  
  466.  
  467. static void 
  468. DeletePage (MEMPAGEHEADER far *p)
  469. {
  470. #ifdef MEM_DEBUG    
  471.     /* Deubgging info... */
  472.     if (MemDebugLevel >= 4) {
  473.     if (PageMemInUse == PageMemInUseMax) 
  474.        fprintf (MemDebugFile, "Page usage is up to %lu\n", PageMemInUseMax);
  475.     }
  476.     if (MemDebugLevel >= MEM_DEBUG_LEVEL) {
  477.     fprintf (MemDebugFile, "PageFree: addr(%lx) id(%u)\n", 
  478.         p, p->id);
  479.     fflush (MemDebugFile);
  480.     }
  481. #endif /* MEM_DEBUG */
  482.  
  483.     PageMemInUse -= p->size;
  484.  
  485.  
  486.     if (p->next == NULL && p->prev == NULL) {
  487.         MemHeader.pages = NULL;
  488.         MemHeader.nr_pages = 0;
  489.     GlobalUnlock (p->handle);
  490.         GlobalFree (p->handle);
  491.     } else {
  492.         if (p == MemHeader.pages) MemHeader.pages = p->next;
  493.         MemHeader.nr_pages--;
  494.  
  495.         if (p->prev != NULL) p->prev->next = p->next;
  496.         if (p->next != NULL) p->next->prev = p->prev;
  497.  
  498.     GlobalUnlock (p->handle);
  499.         GlobalFree (p->handle);
  500.     }
  501. }
  502.  
  503.  
  504. /* 
  505.  * Segmented heap memory allocation. 
  506.  */
  507.  
  508. MemPtr
  509. _MemAlloc (MemSize n, char __far * file, int line)
  510. {
  511.     MEMPAGEHEADER far *p;
  512.     MEMHEADER far *mp;
  513.     char far *cp;
  514.  
  515.     if (n >= 65535) {
  516.     assert (n < 65535);
  517.     goto AllocFail;
  518.     }
  519.     
  520. #if MEM_FAIL_SOON
  521.     if (MemFailSoonLimit != 0 && MemFailSoonLimit < MemInUse + n) {
  522.     MessageBox (NULL, "MemAlloc:  Told to fail here, allocation fails", 
  523.         "Out Of Memory", MB_ICONSTOP | MB_OK);
  524.     return (NULL);
  525.     }
  526. #endif
  527.  
  528.     /* Larger than page size? */
  529.  
  530.     if (n > USEABLESIZE) {
  531.     p = AddPage(n + sizeof(MEMPAGEHEADER) + sizeof(MEMHEADER));
  532.     if (p == NULL)
  533.         goto AllocFail;
  534.  
  535.         mp = p->data;
  536.         mp->magic = MAGIC;
  537.     mp->magic2 = MAGIC2;
  538.     mp->id = MemID++;
  539.         mp->allocated = TRUE;
  540.     
  541.  
  542.         p->used = n;
  543.         p->empty = NULL;
  544.  
  545.         cp = ((char far *) mp) + sizeof(MEMHEADER);
  546. #ifdef MEM_DEBUG
  547.     if (MemDebugLevel >= MEM_DEBUG_LEVEL) {
  548.         fprintf (MemDebugFile, "MemAlloc: addr(%lx) id(%u) size(%ld) global(%d)\n",
  549.             cp, mp->id, (long)n, 0);
  550.         fflush (MemDebugFile);
  551.     }
  552. #endif /* MEM_DEBUG */
  553.  
  554.     MemInUse += n;
  555.     if (MemInUse > MemInUseMax)
  556.         MemInUseMax = MemInUse;
  557.     return ((MemPtr) cp);
  558.     }
  559.  
  560.  
  561.     /* Search for the hole */
  562.  
  563.     for (p = MemHeader.pages; p != NULL; p = p->next) {
  564.         /* Scan the chains */
  565.         if (p->size - p->used - p->overhead <= 0) continue;
  566.         if (p->empty == NULL) continue;
  567.  
  568.         for (mp = p->empty; mp != NULL; mp = mp->next) {
  569.             if (!mp->allocated && mp->size >= n) break;
  570.         }
  571.  
  572.         if (mp != NULL) break;
  573.     }
  574.  
  575.     /* New page needed? */
  576.  
  577.     if (p == NULL) {
  578.         p = AddPage(PAGESIZE);
  579.     if (p == NULL)
  580.         goto AllocFail;
  581.     mp = p->data;
  582.     }
  583.  
  584.     /* Do we need to break it up? */
  585.  
  586.     if (mp->size - n > sizeof(MEMHEADER)) {
  587.         MEMHEADER far *mp2;
  588.  
  589.         cp = ((char far *) mp) + n + sizeof(MEMHEADER);
  590.         mp2 = (MEMHEADER far *) cp;
  591.  
  592.         mp2->magic = 0L;
  593.     mp2->magic2 = 0L;
  594.         mp2->allocated = FALSE;
  595.         mp2->page = p;
  596.         mp2->size = mp->size - n - sizeof(MEMHEADER);
  597.  
  598.         mp2->next = mp->next;
  599.         mp2->prev = mp;
  600.         if (mp->next != NULL) mp->next->prev = mp2;
  601.         mp->next = mp2;
  602.  
  603.  
  604.         p->overhead += sizeof(MEMHEADER);
  605.  
  606.         mp->size = n;
  607.     }
  608.  
  609.     mp->magic = MAGIC;
  610.     mp->magic2 = MAGIC2;
  611.     mp->allocated = TRUE;
  612.     mp->id = MemID++;
  613.  
  614.     p->used += n;
  615.     cp = ((char far *) mp) + sizeof(MEMHEADER);
  616.  
  617.  
  618.     /* Debugging info... */
  619. #ifdef MEM_DEBUG
  620.     if (MemDebugLevel >= MEM_DEBUG_LEVEL) {
  621.     fprintf (MemDebugFile, "MemAlloc: addr(%lx) id(%u) size(%ld) global(%d)\n",
  622.         cp, mp->id, (long)n, 0);
  623.     fflush (MemDebugFile);
  624.     }
  625. #endif /* MEM_DEBUG */
  626.  
  627.     MemInUse += n;
  628.     if (MemInUse > MemInUseMax)
  629.     MemInUseMax = MemInUse;
  630.     
  631.     
  632.     /* Search for the next empty hole */
  633.  
  634.     for (; mp != NULL; mp = mp->next) {
  635.         if (!mp->allocated && mp->size > 0) break;
  636.     }
  637.  
  638.     p->empty = mp;
  639.  
  640.     return ((MemPtr) cp);
  641.     
  642.     
  643. AllocFail:
  644. #if 0
  645.     assert (FALSE /* Memory allocation failed! */);*/
  646. #endif
  647.     return (NULL);
  648. }
  649.  
  650.  
  651.  
  652. /*
  653.  * Segmented heap memory free.
  654.  */
  655. int
  656. _MemFree (MemPtr vp, char __far *file, int line)
  657. {
  658.     MEMPAGEHEADER far *p;
  659.     MEMHEADER far *mp, far *mp2;
  660.     char far *cp;
  661.     
  662.     if (vp == NULL)
  663.         return (0);
  664.     
  665.  
  666.     cp = ((char far *) vp) - sizeof(MEMHEADER);
  667.     mp = (MEMHEADER far *) cp;
  668.  
  669.     if (mp->magic != MAGIC || mp->magic2 != MAGIC2|| !mp->allocated) {
  670.     assert (mp->magic == MAGIC);
  671.     assert (mp->magic2 == MAGIC2);
  672.     assert (mp->allocated);
  673.     return (-1);
  674.     }
  675.     
  676. #ifdef MEM_DEBUG    
  677.     /* Deubgging info... */
  678.     if (MemDebugLevel >= 4) {
  679.     if (MemInUse == MemInUseMax) 
  680.        fprintf (MemDebugFile, "Memory usage is up to %lu\n", MemInUseMax);
  681.     }
  682.     if (MemDebugLevel >= MEM_DEBUG_LEVEL) {
  683.     fprintf (MemDebugFile, "MemFree: addr(%lx) id(%u)\n", vp, mp->id);
  684.     fflush (MemDebugFile);
  685.     }
  686. #endif /* MEM_DEBUG */
  687.  
  688.     MemInUse -= mp->size;
  689.  
  690.  
  691.     p = (MEMPAGEHEADER far *) mp->page;
  692.     p->used -= mp->size;
  693.  
  694.     mp->magic = 0L;
  695.     mp->magic2 = 0L;
  696.     mp->allocated = FALSE;
  697.  
  698.     /* Merge? */
  699.  
  700.     mp2 = mp->prev;
  701.  
  702.     if (mp2 != NULL && !mp2->allocated) {
  703.         mp2->next = mp->next;
  704.         if (mp->next != NULL) mp->next->prev = mp2;
  705.         mp2->size += mp->size + sizeof(MEMHEADER);
  706.  
  707.         p->overhead -= sizeof(MEMHEADER);
  708.  
  709.         mp = mp2;
  710.     }
  711.  
  712.     mp2 = mp->next;
  713.  
  714.     if (mp2 != NULL && !mp2->allocated) {
  715.         mp->next = mp2->next;
  716.         if (mp2->next != NULL) 
  717.         mp2->next->prev = mp;
  718.  
  719.         mp->size += mp2->size + sizeof(MEMHEADER);
  720.  
  721.     p->overhead -= sizeof(MEMHEADER);
  722.     }
  723.  
  724.     if (mp->prev == NULL && mp->next == NULL) {
  725.         DeletePage(p);
  726.     } else {
  727.         if (p->empty == NULL || mp < p->empty) p->empty = mp;
  728.     }
  729.     return (0);
  730. }
  731.  
  732.  
  733.  
  734. MemPtr
  735. _MemRealloc (MemPtr p, MemSize n, char __far *file, int line)
  736. {
  737.     MEMHEADER far *mp;
  738.     char far *cp;
  739.  
  740.     if (p != NULL) {
  741.     /* Block already large enough? */
  742.     cp = ((char far *) p) - sizeof(MEMHEADER);
  743.     mp = (MEMHEADER far *) cp;
  744.  
  745.     if (mp->magic != MAGIC || mp->magic2 != MAGIC2) {
  746.         assert (mp->magic == MAGIC);
  747.         assert (mp->magic2 == MAGIC2);
  748.         return (p);
  749.     }
  750.  
  751.     if (mp->size >= n) return (p);      /* No need to do anything */
  752.     }
  753.     /* Else swap to another block */
  754.  
  755.     cp = MemAlloc (n);
  756.     if (cp == NULL)
  757.     return (NULL);
  758.  
  759.     if (p != NULL) {
  760.     _fmemcpy(cp, p, (size_t)((mp->size >= n) ? n : mp->size));
  761.     MemFree (p);
  762.     }
  763.  
  764.     return ((void far *) cp);
  765. }
  766.  
  767.  
  768.  
  769. void
  770. MemFailSoon (MemSize n)
  771. {
  772. #if MEM_FAIL_SOON
  773.     MemFailSoonLimit = MemInUse + n;
  774. #ifdef MEM_DEBUG
  775.     if (MemDebugLevel >= 1) {
  776.     fprintf (MemDebugFile,
  777.        "MemFailSoon:  Fail when allocation increases by %ld (Max %ld)\n",
  778.         n, MemFailSoonLimit);
  779.     }
  780. #endif
  781. #endif
  782. }
  783.         
  784.  
  785.  
  786.  
  787.  
  788. MemSize
  789. MemBlkSize (MemPtr p)
  790. {
  791.     MEMHEADER far *mp;
  792.     char far *cp;
  793.  
  794.     if (p == NULL) return (0);
  795.     cp = ((char far *) p) - sizeof(MEMHEADER);
  796.  
  797.     mp = (MEMHEADER far *) cp;
  798.  
  799.     if (mp->magic != MAGIC || mp->magic2 != MAGIC2) {
  800.     assert (mp->magic == MAGIC);
  801.     assert (mp->magic2 == MAGIC2);
  802.     return (0);
  803.     }
  804.  
  805.     return (mp->size);
  806. }
  807.  
  808.  
  809. #if 0
  810. MemPtr
  811. MemDup (void far *p)
  812. {
  813.     unsigned int len;
  814.     void far *p1;
  815.  
  816.     len = MgetBlkSize (p);
  817.     p1 = MemAlloc (len);
  818.     if (p1 != NULL)
  819.     _fmemcpy(p1, p, len);
  820.  
  821.     return (p1);
  822. }
  823.  
  824.  
  825. void 
  826. MemoryStatistics (long int *allocated, long int *used, long int *overhead)
  827. {
  828.     MEMPAGEHEADER far *p;
  829.  
  830.     *allocated = *used = *overhead = 0L;
  831.  
  832.     for (p = MemHeader.pages; p != NULL; p = p->next) {
  833.         *allocated += p->size;
  834.         *used += p->used;
  835.         *overhead += p->overhead;
  836.     }
  837. }
  838. #endif
  839.  
  840.  
  841. void 
  842. MemFreeAll (void)
  843. {
  844.     MEMPAGEHEADER far *p, far *p1;
  845.  
  846.     for (p = MemHeader.pages; p != NULL; ) {
  847.     p1 = p->next;
  848.     GlobalUnlock (p->handle);
  849.     GlobalFree (p->handle);
  850.     p = p1;
  851.     }
  852.  
  853.     MemHeader.pages = NULL;
  854.     MemHeader.nr_pages = 0;
  855. }
  856.  
  857.  
  858. #ifdef MEM_DEBUG
  859.  
  860. /* For debugging purposes...  not very pretty */
  861.  
  862. void PrintMemoryChains(void)
  863. {
  864.     MEMPAGEHEADER far *p;
  865.     MEMHEADER far *mp;
  866.     char far *cp;
  867.     char buffer[100];
  868.  
  869.     /* Block already large enough? */
  870.  
  871.  
  872.     for (p = MemHeader.pages; p != NULL; p = p->next) {
  873.         for (mp = p->data; mp != NULL; mp = mp->next) {
  874.             fprintf (MemDebugFile, "%Fp | %u | %s", mp, mp->size, mp->allocated ? "Alloc" : "Free");
  875.         }
  876.     }
  877. }
  878.  
  879. #endif /* DEBUG */
  880.  
  881.  
  882.  
  883. #else        /* !SEGHEAP.  Old version, not used. */
  884.  
  885.  
  886.  
  887.  
  888.  
  889.  
  890.  
  891. /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  892.  *
  893.  *                  Direct memory allocation
  894.  *
  895.  *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
  896.  
  897. /*
  898.  * This following implementation allocates large memory blocks directly 
  899.  * from global memory and small memory blocks from the local heap.  The
  900.  * problem with this method is that pine's local heap is quite small
  901.  * so most of the memory ends up comming from the global heap.
  902.  */
  903.  
  904.  
  905. #define GUARD_LOW0        0xbbbb
  906. #define GUARD_LOW        0x9999
  907. #define GUARD_HIGH        0xaaaaaaaa
  908.  
  909. #define SMALL_MEM_BOUNDRY    32
  910.  
  911. #define HEAP_SIZE        32000
  912.  
  913.  
  914. /* Memory block header.  Placed at beginning of each allocated block. */
  915. typedef struct {            /*size  len */
  916.     WORD        guard0;        /* 00 - 02 */
  917.     HGLOBAL        handle;        /* 02 - 02 */
  918.     short        globalBlk;    /* 04 - 02 */
  919.     MemSize        size;        /* 06 - 04 */
  920.     WORD        id;        /* 0A - 02 */
  921.     WORD        guard1;        /* 0C - 02 */
  922. } MemBlk;                /* Total size:  0E */
  923.  
  924. typedef MemBlk __far *    MemBlkPtr;
  925.  
  926.  
  927. /* Memory high guard tailer.  Placed at end of each allocated block. */
  928. typedef struct {
  929.     unsigned long    guard1;
  930. } MemHighGuard;
  931.  
  932. typedef MemHighGuard __far *MemHighGuardPtr;
  933.  
  934.  
  935. /*
  936.  * Memory allocation globals. 
  937.  */
  938. LOCAL WORD        MemID = 0;        /* Keep track of ID. */
  939. LOCAL unsigned long    MemLocalFails = 0;
  940. LOCAL BOOL        MemLocalFull = FALSE;    /* True when local heap full*/
  941. #ifdef MEM_DEBUG
  942. LOCAL unsigned long    MemInUse = 0;        /* Total bytes in use. */
  943. LOCAL unsigned long    MemInUseMax = 0;    /* max in use at one time. */
  944. LOCAL unsigned long    SmallMemInUse = 0;
  945. LOCAL unsigned long    SmallMemInUseMax = 0;
  946. #endif /* MEM_DEBUG */
  947.  
  948.  
  949.  
  950. /*
  951.  * Allocate a memory block.
  952.  * The file and line indicate where we are called from (for debugging)
  953.  * but in pine these mostly point to a bottel neck routine and are
  954.  * useless.
  955.  */
  956. MemPtr
  957. _MemAlloc (MemSize size, char __far * file, int line)
  958. {
  959.     MemBlkPtr            pBlk;
  960.     MemHighGuardPtr        pHG;
  961.     HGLOBAL            hBlk;
  962.     HLOCAL            hLBlk;
  963.     UINT            totalSize;
  964.     BYTE        __far *    pb;
  965.  
  966.     assert (size <= MEM_BLOCK_SIZE_MAX);
  967.     
  968.  
  969.     /*
  970.      * Calculate total size we need to allocate.
  971.      */
  972.     totalSize = (UINT)size + sizeof (MemBlk) + sizeof (MemHighGuard);
  973.     
  974.     
  975.     pBlk = NULL;
  976.     
  977.     /*
  978.      * If it's a small block and the local heap is not full, try 
  979.      * allocating from the local heap. 
  980.      */
  981.     if (size <= SMALL_MEM_BOUNDRY && !MemLocalFull) {
  982.         
  983.     /* Allocate block from local storage. */
  984.     hLBlk = LocalAlloc (LMEM_MOVEABLE, totalSize);
  985.     if (hLBlk != NULL) {
  986.  
  987.         /* Lock block and dereference. */
  988.         pBlk = (MemBlkPtr) LocalLock (hLBlk);
  989.         if (pBlk != NULL) {
  990.         pBlk->handle = hLBlk;
  991.         pBlk->globalBlk = FALSE;
  992.         }
  993.         else 
  994.             LocalFree (hLBlk);
  995.     }
  996.     else {
  997.         ++MemLocalFails;
  998.         MemLocalFull = TRUE;
  999. #ifdef MEM_DEBUG
  1000.         if (MemDebugLevel >= MEM_DEBUG_LEVEL)
  1001.         fprintf (MemDebugFile, "Local Memory alloc failed, %lu fails, %lu bytes in use\n",
  1002.             MemLocalFails, SmallMemInUse);
  1003. #endif
  1004.     }
  1005.     }
  1006.  
  1007.     
  1008.     /* 
  1009.      * If it is a large block, or local alloc failed, we allocate from
  1010.      * global space. 
  1011.      */
  1012.     if (pBlk == NULL) {
  1013.         
  1014.     /* Allocate block from global storage. */
  1015.     hBlk = GlobalAlloc (GMEM_MOVEABLE, totalSize);
  1016.     if (hBlk == NULL) 
  1017.         return (NULL);
  1018.  
  1019.  
  1020.     /* Lock block and dereference. */
  1021.     pBlk = (MemBlkPtr) GlobalLock (hBlk);
  1022.     if (pBlk == NULL) {
  1023.         GlobalFree (hBlk);
  1024.         return (NULL);
  1025.     }
  1026.     pBlk->handle = hBlk;
  1027.     pBlk->globalBlk = TRUE;
  1028.     }
  1029.  
  1030.  
  1031.     
  1032.     /* Fill rest of header. */
  1033.     pBlk->guard0 = GUARD_LOW0;
  1034.     pBlk->size = size;
  1035.     pBlk->id = ++MemID;
  1036.     pBlk->guard1 = GUARD_LOW;
  1037.  
  1038.     
  1039.     /* Find address that will be returned to caller. */
  1040.     pb = (BYTE __far *) (pBlk + 1);
  1041.  
  1042.     
  1043.     /* Find high guard and fill. */
  1044.     pHG = (MemHighGuardPtr) (pb + size);
  1045.     pHG->guard1 = GUARD_HIGH;
  1046.     
  1047.  
  1048.     /* Debugging info... */
  1049. #ifdef MEM_DEBUG
  1050.     if (MemDebugLevel >= MEM_DEBUG_LEVEL) {
  1051.     if( !file ) file = "??";
  1052.     fprintf (MemDebugFile, "MemAlloc: addr(%lx) id(%u) size(%ld) global(%d)\n",
  1053.         pb, pBlk->id, (long)size, pBlk->globalBlk);
  1054.     fflush (MemDebugFile);
  1055.     }
  1056.     MemInUse += totalSize;
  1057.     if (MemInUse > MemInUseMax)
  1058.     MemInUseMax = MemInUse;
  1059.     if (size <= SMALL_MEM_BOUNDRY) {
  1060.     SmallMemInUse += totalSize;
  1061.     if (SmallMemInUse > SmallMemInUseMax)
  1062.         SmallMemInUseMax = SmallMemInUse;
  1063.     }
  1064. #endif /* MEM_DEBUG */
  1065.     
  1066.  
  1067.     return ((MemPtr) pb);
  1068. }
  1069.  
  1070.  
  1071.  
  1072.  
  1073. /*
  1074.  * Free a block.
  1075.  */
  1076. int
  1077. _MemFree (MemPtr block, char __far *file, int line)
  1078. {
  1079.     MemBlkPtr        pBlk;
  1080.     MemHighGuardPtr    pHG;
  1081.     HGLOBAL        hBlk;
  1082.     HLOCAL        hLBlk;
  1083.     BOOL        brc;
  1084.     UINT        totalSize;
  1085.     
  1086.     if (block == NULL)
  1087.         return (0);
  1088.  
  1089.  
  1090.     /* Find header and high guard and check them. */
  1091.     pBlk = ((MemBlkPtr)block) - 1;
  1092.     pHG = (MemHighGuardPtr) ((char __far *)block + pBlk->size);
  1093.     
  1094.     totalSize = pBlk->size + sizeof (MemBlk) + sizeof (MemHighGuard);
  1095.  
  1096.     /* If these changed them someone wrote where the should not have. */
  1097.     assert (pBlk->guard0 == GUARD_LOW0);
  1098.     assert (pBlk->guard1 == GUARD_LOW);
  1099.     assert (pHG->guard1 == GUARD_HIGH);
  1100.  
  1101.  
  1102.     
  1103. #ifdef MEM_DEBUG    
  1104.     /* Deubgging info... */
  1105.     if (MemDebugLevel >= MEM_DEBUG_LEVEL) {
  1106.     if (pBlk->size <= SMALL_MEM_BOUNDRY && 
  1107.         SmallMemInUse == SmallMemInUseMax) 
  1108.        fprintf (MemDebugFile, "Small memory usage is up to %lu\n", SmallMemInUseMax);
  1109.     if (MemInUse == MemInUseMax) 
  1110.        fprintf (MemDebugFile, "Memory usage is up to %lu\n", MemInUseMax);
  1111.     }
  1112.     MemInUse -= totalSize;
  1113.     if (pBlk->size <= SMALL_MEM_BOUNDRY)
  1114.         SmallMemInUse -= totalSize;
  1115.     if (MemDebugLevel >= MEM_DEBUG_LEVEL) {
  1116.     fprintf (MemDebugFile, "MemFree: addr(%lx) id(%u)\n", 
  1117.         block, pBlk->id);
  1118.     fflush (MemDebugFile);
  1119.     }
  1120. #endif /* MEM_DEBUG */
  1121.  
  1122.  
  1123.  
  1124.     /*
  1125.      * Header indicates which block it came from
  1126.      */
  1127.     if (!pBlk->globalBlk) {
  1128.     /* Unlock block */
  1129.     hLBlk = pBlk->handle;
  1130.     brc = LocalUnlock (hLBlk);
  1131.     assert (!brc);
  1132.  
  1133.     /* And free block. */
  1134.     hLBlk = LocalFree (hLBlk);
  1135.     assert (hLBlk == NULL);
  1136.     MemLocalFull = FALSE;
  1137.     }
  1138.     else {
  1139.     /* Unlock block */
  1140.     hBlk = pBlk->handle;
  1141.     brc = GlobalUnlock (hBlk);
  1142.     assert (!brc);
  1143.  
  1144.     /* And free block. */
  1145.     hBlk = GlobalFree (hBlk);
  1146.     assert (hBlk == NULL);
  1147.     }
  1148.     return (0);
  1149. }
  1150.  
  1151.  
  1152.  
  1153.  
  1154. /*
  1155.  * Reallocate a memory block.  Simplistic approach.
  1156.  */
  1157. MemPtr
  1158. _MemRealloc (MemPtr block, MemSize size, char __far * file, int line)
  1159. {
  1160.     MemPtr    newBlock;
  1161.     
  1162.     
  1163.     newBlock = MemAlloc (size);
  1164.     if (newBlock == NULL)
  1165.     return (NULL);
  1166.  
  1167.     if (block != NULL) {
  1168.     _fmemcpy (newBlock, block , (size_t)MIN (size, MemBlkSize (block)));
  1169.     MemFree (block);
  1170.     }
  1171.     
  1172.     return (newBlock);
  1173. }
  1174.     
  1175.     
  1176.  
  1177. /*
  1178.  * Return the size of a memory block
  1179.  */
  1180. MemSize
  1181. MemBlkSize (MemPtr block)
  1182. {
  1183.     MemBlkPtr            pBlk;
  1184.  
  1185.     if (block == NULL) return (0);
  1186.     pBlk = ((MemBlkPtr)block) - 1;
  1187.     assert (pBlk->guard1 == GUARD_LOW);
  1188.  
  1189.     return (pBlk->size);
  1190. }
  1191.  
  1192.  
  1193. #ifdef MEM_DEBUG
  1194. struct testblock {
  1195.     struct testblock    __far * prev;
  1196.     HLOCAL            h;
  1197. };
  1198.  
  1199.  
  1200.  
  1201. void
  1202. MemATest (void)
  1203. {
  1204.     void    __near        *n;
  1205.     struct testblock __far    *p;
  1206.     struct testblock __far    *pnew;
  1207.     HLOCAL            hl;
  1208.     int                bcount;
  1209.     UINT            segment, start, end;
  1210.     void    __far        *f;
  1211.     HGLOBAL            hg;
  1212.     DWORD            dw;
  1213.     LOCALINFO            li;
  1214.     UINT            DataSeg;
  1215.     
  1216. #if 0  
  1217.     hg = GlobalAlloc (GMEM_FIXED, HEAP_SIZE);    /* Allocate global block */
  1218.     if (hg == NULL)
  1219.     return;
  1220.     f = GlobalLock (hg);            /* Lock and get pointer. */
  1221.     if (f == NULL) 
  1222.     goto Fail1;
  1223.     segment = (UINT) GET_SEGMENT (f);        /* Get segment and offsets. */
  1224.     start = (UINT) GET_OFFSET (f);
  1225.     end = start + HEAP_SIZE - 1;
  1226.     start += 16;
  1227.     if (!LocalInit (segment, start, end))        /* Init it as the local heap*/
  1228.     goto Fail2;
  1229. #endif
  1230. #if 0
  1231.     __asm MOV DataSeg,DS;            /* Get current DS. */
  1232.     __asm MOV DS,segment;            /* Set DS to new heap. */
  1233.     hl = LocalAlloc (0, SMALL_MEM_BOUNDRY);    /* Now allocate something. */
  1234.     __asm MOV DS,DataSeg;            /* Restore DS. */
  1235.     if (hl == NULL) 
  1236.         return;
  1237.     n = LocalLock (hl);                /* Find where it is. */
  1238.     f = (void __far *)n;
  1239.     segment = GET_SEGMENT(f);            /* What Segment. */
  1240.     dw = GlobalHandle (segment);
  1241.     hg = (HGLOBAL) (dw & 0xffff);
  1242.     if (hg == NULL)
  1243.         return;
  1244.     
  1245.     li.dwSize = sizeof (li);            /* What size. */
  1246.     if (!LocalInfo (&li, hg))
  1247.         return;
  1248.     
  1249.     dw = GlobalSize (hg);
  1250.     f = GlobalLock (hg);
  1251.     GlobalUnlock (hg);
  1252.     
  1253.     LocalUnlock (hl);
  1254.     LocalFree (hl);
  1255.  
  1256.     
  1257. #endif
  1258.     
  1259.     
  1260.     
  1261.     
  1262.     p = NULL;
  1263.     pnew = NULL;
  1264.     bcount = 0;
  1265.     
  1266.     do {
  1267.     hl = LocalAlloc (0, SMALL_MEM_BOUNDRY);
  1268.     if (hl != NULL) {
  1269.         ++bcount;
  1270.         n = LocalLock (hl);
  1271.         pnew = (struct testblock __far*) n;
  1272.         pnew->h = hl;
  1273.         pnew->prev = p;
  1274.         p = pnew;
  1275.         }
  1276.     } while (hl != NULL);
  1277.     
  1278.     
  1279.     if (MemDebugFile != NULL)
  1280.     fprintf (MemDebugFile, "Allocated %d blocks of size %d\n",
  1281.         bcount, SMALL_MEM_BOUNDRY);
  1282.             
  1283.     while (p != NULL) {
  1284.     pnew = p->prev;
  1285.     hl = p->h;
  1286.     LocalUnlock (hl);
  1287.     LocalFree (hl);
  1288.     p = pnew;
  1289.     }
  1290.     fflush (MemDebugFile);
  1291. #if 0 
  1292. Fail2:    GlobalUnlock (hg);
  1293. Fail1:    GlobalFree (hg);
  1294. #endif
  1295.     return;
  1296. }
  1297. #endif /* MEM_DEBUG */
  1298.  
  1299. #endif /* ifdef SEGHEAP */
  1300.  
  1301. #endif    /* MSC_MALLOC */
  1302.